package com.gipson.amc.service.basicdata;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsbj.common.msg.ResponseMessage;
import com.gipson.amc.entity.Application;
import com.gipson.amc.entity.Authority;
import com.gipson.amc.mapper.ApplicationMapper;
import com.gipson.amc.mapper.AuthorityMapper;
import com.gipson.amc.model.Menu;
import com.gipson.amc.utils.Constants;
import com.gipson.amc.utils.PropertyUtil;
import com.gipson.amc.utils.listprocess.ListProcess;
import com.gipson.amc.utils.sort.AuthorityComparator;
import com.gipson.amc.utils.strprocess.ObjectParse;
import com.gipson.amc.utils.strprocess.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author xsyuan
 * @since 2020-03-27
 */
@Service
public class AuthorityService extends ServiceImpl<AuthorityMapper, Authority> {
	
	public static Logger logger = LoggerFactory.getLogger(AuthorityService.class);
	
	@Resource
	private ApplicationService applicationService;
	
	
	public List<Authority> listByRoleId(String roleId) {
		return baseMapper.listByRoleId(roleId);
	}
	
	
	public List<Menu> getAllMenuByUsername(String username, String applicationId) {
		List<Menu> menuList = baseMapper.getAllMenuByUsername(username, applicationId).stream().map(x -> {
			Menu menu = new Menu();
			menu.setId(x.getCode());
			menu.setName(x.getName());
			menu.setParentId(StringUtils.isNotBlank(x.getParentCode()) ? x.getParentCode() : "");
			menu.setSortNo(x.getSort());
			menu.setIcon(x.getIcon());
			menu.setImgUrl(x.getImgUrl());
			menu.setDataUrl(x.getHref());
			return menu;
		}).collect(Collectors.collectingAndThen(
				Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Menu::getId))), ArrayList::new));
		return menuList;
	}
	
	/**
	 * 获取权限列表,并根据authority.code升序排序。
	 * 传入参数: applicationId
	 *
	 * @param
	 * @return
	 * @author cjw 2020-03-28
	 */
	public List<Authority> getAuthority(String applicationId) {
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaQuery()
				.eq(StrUtil.isNotEmpty(applicationId), Authority::getApplicationId, applicationId)
				.orderByAsc(Authority::getCode);
		List<Authority> list_authority = baseMapper.selectList(wrapper);
		return list_authority;
	}
	
	/**
	 * 根据nameDim,applicationId模糊查询authority列表。
	 * <br><br>该方法的流程为:
	 * <br>1、根据nameDim,applicationId模糊查询,获得authority列表(list_authority)。
	 * <br>1-2、若nameDim为空,则可直接返回list_authority列表。
	 * <br>2、遍历list_authority中每个authority，查询其包含的子authority列表(list_authority_sub),并存入list_authority_final中。
	 * <br>3、去除list_authority_final中的重复项, 并根据authority.code升序排序, 最后返回该authority列表。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-03-28
	 */
	public List<Authority> getAuthorityByNameDimByApplicationId(String nameDim, String applicationId) {
		/**
		 * 1、根据nameDim,applicationId模糊查询,获得authority列表(list_authority)。
		 */
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaQuery()
				.like(StrUtil.isNotEmpty(nameDim), Authority::getName, nameDim)
				.eq(StrUtil.isNotEmpty(applicationId), Authority::getApplicationId, applicationId)
				.orderByAsc(Authority::getCode);
		List<Authority> list_authority = baseMapper.selectList(wrapper);
		
		/**
		 * 1-2、若nameDim为空,则可直接返回list_authority列表。
		 */
		if(StrUtil.isEmpty(nameDim)){
			return list_authority;
		}
		
		/**
		 * 2、遍历list_authority中每个authority，查询其包含的子authority列表(list_authority_sub),并存入list_authority_final中。
		 */
		List<Authority> list_authority_final = new ArrayList<>();
		
		for (Authority authority : list_authority) {
			//根据authority.code,applicationId模糊查询,获得list_authority_sub。
			wrapper = Wrappers.<Authority>lambdaQuery()
					.likeRight(Authority::getCode, authority.getCode())
					.eq(StrUtil.isNotEmpty(applicationId), Authority::getApplicationId, applicationId)
					.orderByAsc(Authority::getCode);
			List<Authority> list_authority_sub = baseMapper.selectList(wrapper);
			//将list_authority_sub存入list_authority中。
			list_authority_final.addAll(list_authority_sub);
		}
		
		/**
		 * 3、去除list_authority_final中的重复项, 并根据authority.code升序排序, 最后返回该authority列表。
		 */
		list_authority_final = removeDuplicateAuthority(list_authority_final);
		//当前list_authority_final已按authority.code升序排序。
		return list_authority_final;
	}
	
	/**
	 * 产生输出的authority信息。以树状结构输出list_authority。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-06
	 */
	public static JSONArray generateAuthority(List<Authority> list_authority) {
		if (list_authority == null) {
			return null;
		}
		//将list_authority转为树状结构的数据
		JSONArray json_array = JSONArray.parseArray(JSON.toJSONString(list_authority, SerializerFeature.WriteMapNullValue));
		JSONArray json_array2 = ListProcess.listToTree(json_array, "code", "parentCode", "children");
		return json_array2;
	}
	
	public List<Authority> getAuthList(Map<Object, Object> map) {
		List<Authority> authorityList = baseMapper.getAllMenu(map);
		return authorityList;
	}
	
	/**
	 * 检查authority》检查code,name是否有效。code,name不可重复。
	 * 传入参数: id,code,name,applicationId其中code,name,applicationId均需含有内容。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-07
	 */
	public ResponseMessage checkAuthorityForCodeAndName(String id, String code, String name, String applicationId) {
		if (StrUtil.isEmpty(code) || StrUtil.isEmpty(name) || StrUtil.isEmpty(applicationId)) {
			logger.error("传入的code,name,applicationId存在空值,未执行该方法!");
			return ResponseMessage.error("code,name,applicationId存在空值, 未执行该方法!");
		}
		
		//检查code是否重复
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaQuery()
				.ne(StrUtil.isNotEmpty(id), Authority::getId, id)
				.eq(Authority::getCode, code)
				.eq(Authority::getApplicationId, applicationId);
		List<Authority> list_authority = baseMapper.selectList(wrapper);
		if (list_authority.size() > 0) {
			return ResponseMessage.error("菜单编号(code)已存在,请重新输入菜单编号(code)!");
		}
		
		//检查name是否重复
		wrapper = Wrappers.<Authority>lambdaQuery()
				.ne(StrUtil.isNotEmpty(id), Authority::getId, id)
				.eq(Authority::getName, name)
				.eq(Authority::getApplicationId, applicationId);
		list_authority = baseMapper.selectList(wrapper);
		if (list_authority.size() > 0) {
			return ResponseMessage.error("菜单名称(name)已存在,请重新输入菜单名称(name)!");
		}
		//code,name有效,返回成功信息
		return ResponseMessage.ok();
	}
	
	/**
	 * 根据code获取authority。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-08
	 */
	public Authority getAuthorityByCode(String code) {
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaQuery()
				.eq(Authority::getCode, code);
		Authority authority = baseMapper.selectOne(wrapper);
		return authority;
	}
	
	/**
	 * 补充authority,为authority中的新增字段赋值。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-08
	 */
	public Authority supplementAuthority(Authority authority) {
		if (authority == null) {
			return null;
		}
		//上级菜单名称
		if (StrUtil.isNotEmpty(authority.getParentCode())) {
			Authority authority_temp = getAuthorityByCode(authority.getParentCode());
			authority.setParentName(authority_temp.getName());
		}
		//系统编号
		if (StrUtil.isNotEmpty(authority.getApplicationId())) {
			Application application = applicationService.getById(authority.getApplicationId());
			authority.setApplicationCode(application.getApplicationCode());
			authority.setApplicationName(application.getApplicationName());
		}
		return authority;
	}
	
	/**
	 * 根据id删除authority, 若该authority下含有子菜单,会被一并删除。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-08
	 */
	@Transactional
	public ResponseMessage deleteAuthority(String id) {
		//根据id获取对应的authority信息
		Authority authority = baseMapper.selectById(id);
		if (authority == null) {
			return ResponseMessage.error("未找到该id对应的authority信息!,id=" + id);
		}
		//删除authority.code下的所有菜单
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaQuery()
				.likeRight(Authority::getCode, authority.getCode())
				.eq(Authority::getApplicationId, authority.getApplicationId());
		baseMapper.delete(wrapper);
		return ResponseMessage.ok();
	}
	
	/**
	 * 去除list_authority中的重复项。此处根据authority.id判断二者是否重复。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-08
	 */
	public static List<Authority> removeDuplicateAuthority(List<Authority> list_authority) {
		if (list_authority == null) {
			return null;
		}
		//mapId的键值对格式为《"id=id_1", null》
		Map<String, Object> mapId = new HashMap<>();
		List<Authority> list_authority_washed = new ArrayList<>();
		
		for (Authority authority : list_authority) {
			String key = "id=" + authority.getId();
			//若mapId中不含有该key
			if (!mapId.containsKey(key)) {
				//将authority存入list_authority_washed中。
				list_authority_washed.add(authority);
				//将key存入mapId中
				mapId.put(key, null);
			}
		}
		return list_authority_washed;
	}
	
	/**
	 * 根据id强制更新authority。若字段值为null,亦更新。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-12
	 */
	@Transactional
	public String updateAuthorityByIdForcedly(Authority authority) {
		//StrUtil.prettyPrint("updateAuthorityByIdForcedly().authority", authority);
		Wrapper<Authority> wrapper = Wrappers.<Authority>lambdaUpdate()
				.set(Authority::getId, authority.getId())
				.set(Authority::getParentCode, authority.getParentCode() == null ? "" : authority.getParentCode())
				.set(Authority::getCode, authority.getCode() == null ? "" : authority.getCode())
				.set(Authority::getName, authority.getName() == null ? "" : authority.getName())
				.set(Authority::getType, authority.getType() == null ? "" : authority.getType())
				.set(Authority::getPermission, authority.getPermission() == null ? "" : authority.getPermission())
				.set(Authority::getHref, authority.getHref() == null ? "" : authority.getHref())
				.set(Authority::getIcon, authority.getIcon() == null ? "" : authority.getIcon())
				.set(Authority::getImgUrl, authority.getImgUrl() == null ? "" : authority.getImgUrl())
				.set(Authority::getSort, authority.getSort() == null ? "" : authority.getSort())
				.eq(Authority::getId, authority.getId());
		baseMapper.update(null, wrapper);
		return Constants.SUCCESS;
	}
	
	/**
	 * 获取imgUrl列表。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-12
	 */
	public static List<String> getImgUrlList() {
		List<String> list_imgUrl = new ArrayList<>();
		for (int i = 0; i < 12; i++) {
			String imgUrl = "/imgs/bgc/" + (i + 1) + ".png";
			list_imgUrl.add(imgUrl);
		}
		return list_imgUrl;
	}
	
	/**
	 * 根据authorityId获取完整的authority信息(包含"连表查询字段")。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-05-12
	 */
	public Authority getAuthorityFullById(String authorityId) {
		Authority authority = baseMapper.selectById(authorityId);
		//补充authority,为authority中的新增字段赋值。
		supplementAuthority(authority);
		return authority;
	}
	
	/**
	 * 更新authority信息。该方法包括解析参数,验证参数,更新authority等步骤。
	 *
	 * @param
	 * @return
	 * @author cjw 2020-06-02
	 */
	@Transactional
	public ResponseMessage updateAuthority(Authority authority) {
		
		//解析传来的参数
		if (StrUtil.isEmpty(authority.getId())) {
			return ResponseMessage.error("id为空!");
		}
		if (StrUtil.isEmpty(authority.getApplicationId())) {
			return ResponseMessage.error("applicationId为空!");
		}
		if (StrUtil.isEmpty(authority.getCode())) {
			return ResponseMessage.error("code为空!");
		}
		if (StrUtil.isEmpty(authority.getName())) {
			return ResponseMessage.error("name为空!");
		}
		if (StrUtil.isEmpty(authority.getType())) {
			return ResponseMessage.error("type为空!");
		}
		
		/**
		 * 验证传入的参数是否有效。
		 * 检查authority》检查code,name是否有效。
		 */
		ResponseMessage responseMessageTemp = checkAuthorityForCodeAndName(authority.getId(), authority.getCode(), authority.getName(), authority.getApplicationId());
		if (!responseMessageTemp.isSuccess()) {
			return responseMessageTemp;
		}
		
		/**
		 * 更新authority信息。
		 */
		Authority authorityOrigin = getById(authority.getId());
		if (authorityOrigin == null) {
			return ResponseMessage.error("未找到id对应的authority信息!");
		}
		
		authorityOrigin.setId(authority.getId());
		authorityOrigin.setApplicationId(authority.getApplicationId());
		authorityOrigin.setParentCode(authority.getParentCode());
		authorityOrigin.setCode(authority.getCode());
		authorityOrigin.setName(authority.getName());
		authorityOrigin.setType(authority.getType());
		authorityOrigin.setPermission(authority.getPermission());
		authorityOrigin.setHref(authority.getHref());
		authorityOrigin.setIcon(authority.getIcon());
		authorityOrigin.setImgUrl(authority.getImgUrl());
		authorityOrigin.setSort(authority.getSort());
		//根据id强制更新authority。
		updateAuthorityByIdForcedly(authorityOrigin);
		return ResponseMessage.ok();
	}
	
	
	/**
	 * @param
	 * @return
	 * @author cjw 2020-05-06
	 */
	public static void main(String[] args) {
	
	}
}
